﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Web;
using Toolkit.Web.Helpers;
using Toolkit.Web.ExtensionMethods;
using System.ComponentModel;

namespace Toolkit.Web.ViewComponents.DataGrid
{
    public interface IDataGridInputModel
    {
        DataGridRenderMode RenderMode
        {
            get;
            set;
        }

        IDataGridSelectionInputModel SelectionInput
        {
            get;
            set;
        }

        int RecordStartIndex
        {
            get;
            set;
        }

        int? RecordSetSize
        {
            get;
            set;
        }

        IDataExpressionInputModel SortByColumnExpression
        {
            get;
            set;
        }

        bool IsSortedInDescendingOrder
        {
            get;
            set;
        }

        int? MaximumViewPortHeight
        {
            get;
            set;
        }

        IList<IDataGridColumnInputModel> Columns
        {
            get;
            set;
        }

        void ApplyPersistentSettings(IPersistentDataGridModel settings);

        void ApplyPersistentSettings(HttpCookie cookie);

        IDataGridColumnInputModel GetColumn(string key);

        void CleanModel();
    }

    [DataContract]
    public class DataGridInputModel : IDataGridInputModel, IPersistentDataGridModel
    {
        public DataGridInputModel()
        {
        }

        public DataGridInputModel(IPersistentDataGridModel settings)
            : this()
        {
            SetPersistentSettings(settings);
        }

        public DataGridInputModel(HttpRequest request, string prefix)
            : this()
        {
            if (request == null)
            {
                return;
            }

            if (prefix == null)
            {
                prefix = string.Empty;
            }

            if (!string.IsNullOrEmpty(prefix) && !prefix.EndsWith("."))
            {
                prefix += ".";
            }

            RenderMode = (DataGridRenderMode)request.GetValue<int>(prefix + "RenderMode");
            RecordStartIndex = request.GetValue<int>(prefix + "RecordStartIndex");
            RecordSetSize = request.GetNullableValue<int>(prefix + "RecordSetSize");
            SortByColumnExpression.Encoded = request.GetValue(prefix + "SortByColumnExpression.Encoded");
            SortByColumnExpression.Encrypted = request.GetValue(prefix + "SortByColumnExpression.Encrypted");
            IsSortedInDescendingOrder = request.GetValue<bool>(prefix + "IsSortedInDescendingOrder");
            MaximumViewPortHeight = request.GetNullableValue<int>(prefix + "MaximumViewPortHeight");

            Columns = request.GetValues<DataGridColumnInputModel>(prefix + "Columns", (item, req, key) =>
            {
                item.Key = req.GetValue(key + "Key");
                item.Index = req.GetNullableValue<int>(key + "Index");
                item.Width = req.GetNullableValue<int>(key + "Width");
                item.IsVisible = req.GetValue<bool>(key + "IsVisible");
                item.RenderedIndex = req.GetNullableValue<int>(key + "RenderedIndex");
            }).ToList();

            SelectionInput = new DataGridSelectionInputModel();
            SelectionInput.IncludeInSelectionByDefault = request.GetValue<bool>(prefix + "SelectionInput.IncludeInSelectionByDefault");
            SelectionInput.IncludeInSelection = request.GetValues(prefix + "SelectionInput.IncludeInSelection").ToList();
            SelectionInput.ExcludeFromSelection = request.GetValues(prefix + "SelectionInput.ExcludeFromSelection").ToList();
        }

        [DataMember]
        public DataGridRenderMode RenderMode
        {
            get;
            set;
        }

        [DataMember]
        public int RecordStartIndex
        {
            get;
            set;
        }

        [DataMember]
        public int? RecordSetSize
        {
            get;
            set;
        }

        [DataMember]
        public DataExpressionInputModel SortByColumnExpression
        {
            get;
            set;
        }

        IPersistentDataExpressionModel IPersistentDataGridModel.SortByColumnExpression
        {
            get
            {
                if (SortByColumnExpression != null)
                {
                    return ((IPersistentDataExpressionModel)SortByColumnExpression);
                }
                return null;
            }
            set
            {
                if (value != null)
                {
                    SortByColumnExpression = ((DataExpressionInputModel)value);
                }
                else
                {
                    SortByColumnExpression = null;
                };
            }
        }

        IDataExpressionInputModel IDataGridInputModel.SortByColumnExpression
        {
            get
            {
                if (SortByColumnExpression != null)
                {
                    return ((IDataExpressionInputModel)SortByColumnExpression);
                }
                return null;
            }
            set
            {
                if (value != null)
                {
                    SortByColumnExpression = ((DataExpressionInputModel)value);
                }
                else
                {
                    SortByColumnExpression = null;
                };
            }
        }

        [DataMember]
        public bool IsSortedInDescendingOrder
        {
            get;
            set;
        }

        [DataMember]
        public int? MaximumViewPortHeight
        {
            get;
            set;
        }

        [DataMember]
        public List<DataGridColumnInputModel> Columns
        {
            get;
            set;
        }

        IList<IPersistentDataGridColumnModel> IPersistentDataGridModel.Columns
        {
            get
            {
                if (Columns != null)
                {
                    return ((IEnumerable<IPersistentDataGridColumnModel>)Columns).ToList();
                }
                return null;
            }
            set
            {
                if (value != null)
                {
                    Columns = value.ToList().ConvertAll(column => new DataGridColumnInputModel(column));
                }
                else
                {
                    Columns = null;
                }
            }
        }

        IList<IDataGridColumnInputModel> IDataGridInputModel.Columns
        {
            get
            {
                if (Columns != null)
                {
                    return ((IEnumerable<IDataGridColumnInputModel>)Columns).ToList();
                }
                return null;
            }
            set
            {
                if (value != null)
                {
                    Columns = ((IEnumerable<DataGridColumnInputModel>)value).ToList();
                }
                else
                {
                    Columns = null;
                };
            }
        }

        public DataGridSelectionInputModel SelectionInput
        {
            get;
            set;
        }

        IDataGridSelectionInputModel IDataGridInputModel.SelectionInput
        {
            get
            {
                if (SelectionInput != null)
                {
                    return SelectionInput;
                }
                return null;
            }
            set
            {
                SelectionInput = (DataGridSelectionInputModel)value;
            }
        }

        public void ApplyPersistentSettings(IPersistentDataGridModel settings)
        {
            if (settings == null)
            {
                return;
            }

            // Have any values been set? This is not exact because not all properties are nullable.
            bool valuesHaveBeenSet = (
                RecordStartIndex > 0 ||
                RecordSetSize.HasValue ||
                (SortByColumnExpression != null && !string.IsNullOrEmpty(SortByColumnExpression.Value)) ||
                IsSortedInDescendingOrder ||
                MaximumViewPortHeight.HasValue ||
                (Columns != null && Columns.Count > 0)
            );

            if (valuesHaveBeenSet)
            {
                return;
            }

            SetPersistentSettings(settings);
        }

        public void ApplyPersistentSettings(HttpCookie cookie)
        {
            if (cookie == null)
            {
                return;
            }

            IPersistentDataGridModel persistentSettings = null;

            try
            {
                persistentSettings = JsonSerialization.Deserialize<PersistentDataGridModel>(cookie.Value);
            }
            catch (Exception)
            {
                return;
            }

            ApplyPersistentSettings(persistentSettings);
        }

        public IDataGridColumnInputModel GetColumn(string key)
        {
            if (Columns == null)
            {
                return null;
            }
            return Columns.FirstOrDefault(c => !string.IsNullOrEmpty(c.Key) && c.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
        }

        public void CleanModel()
        {
            if (Columns != null)
            {
                foreach (DataGridColumnInputModel column in Columns)
                {
                    column.CleanModel();
                }
            }
        }

        private void SetPersistentSettings(IPersistentDataGridModel settings)
        {
            if (settings == null)
            {
                return;
            }

            RecordStartIndex = settings.RecordStartIndex;
            RecordSetSize = settings.RecordSetSize;
            SortByColumnExpression = (DataExpressionInputModel)settings.SortByColumnExpression;
            IsSortedInDescendingOrder = settings.IsSortedInDescendingOrder;
            MaximumViewPortHeight = settings.MaximumViewPortHeight;

            if (settings.Columns != null)
            {
                Columns = settings.Columns.ToList().ConvertAll(column => new DataGridColumnInputModel(column));
            }
            else
            {
                Columns = null;
            }
        }
    }
}
